 
<!--
 * @Descripttion:
 * @Author: yuxi
 * @Date: 2020-12-01 14:09:20
 * @LastEditors: yuxi
 * @LastEditTime: 2020-12-03 09:59:22
-->
<template>
  <div class="scroll-list"
       @mousewheel.stop="handleMouseWheel"
       @mouseenter.capture.stop="handleMouseEnter"
       @mouseleave.capture.stop="handleMouseOut">
    <div style="padding: 0px; margin: 0px; position: relative;"
         ref="scrollBar">
      <slot></slot>
    </div>
  </div>
</template>

<script>
window.requestAnimationFrame = window.requestAnimationFrame||function (fn) {return setTimeout(fn,1000/60)}
window.cancelAnimationFrame = window.cancelAnimationFrame ||clearTimeout
export default {
  name: 'VueInfiniteScroll',
  props: {
    active: {
      type: Boolean,
      default () {
        return true
      }
    },
    delay: {
      type: Number,
      default () {
        return 3000
      }
    },
    direction: {
      type: String,
      default () {
        return 'up'
      }
    },
  },
  mounted () {
    setTimeout(() => {
      this.start()
    }, this.delay)
  },
  data () {
    return {
      pause: false,
      childrenNode: [],
      dyOffset: [],
      reqId: ''
    }
  },
  watch: {
    pause () {
      if (!this.pause) {
        setTimeout(this.start, this.delay)
      }
    }
  },
  computed: {
    scrolling () {
      return this.active && !this.pause
    }
  },
  methods: {
    getUseableSlots () {
      // 查询子节点
      return this.$slots.default.filter(f => { 
        return f.tag !== undefined
      })
    },
    start () {
      if (!this.scrolling) return
      // console.log('-start-')
      let scrollHeight = this.$refs.scrollBar.offsetHeight
      // 查找显示元素
      let scrollY = 0
      this.childrenNode = this.getUseableSlots().map((r, i) => {
        let { offsetTop, offsetHeight } = r.elm
        this.setDefault()
        // console.log(window.getComputedStyle( r.elm))
        let tY = this.dyOffset[i]
        let top = offsetTop - tY
        // console.log('top', top, ' clientHeight + top', offsetHeight + top)
        // 横跨上边线或者贴着上边线item
        if (this.direction === 'up' && top <= 0 && offsetHeight + top > 0) {
          // 带滚动到元素
          // console.log('Match item index ', i)
          scrollY = offsetHeight + top // 向上移动距离
        } else if (this.direction === 'down' && top > 0 && top < scrollHeight && offsetHeight + top >= scrollHeight) {
          // console.log('Match item index ', i)
          scrollY = top - scrollHeight  // 向下移动距离
        }
      })
      // console.log('-start-', 'scrollY', scrollY)
      this.to(scrollY, 0, Math.abs(scrollY) / scrollY, () => {
        setTimeout(() => {
          this.start()
        }, this.delay)
      })
    },
    to (to, now, step, cb) {
      // console.log('to', ...arguments)
      if (!this.scrolling) {
        return
      }
      if (to > 0 && now >= to) {
        cb()
        return
      } else if (to < 0 && now <= to) {
        cb()
        return
      }
      this.scrollBy(0, step)
      if (this.reqId) {
        cancelAnimationFrame(this.reqId) 
      }
      this.reqId = window.requestAnimationFrame(() => {
        this.to(to, now + step, step, cb)
      })
    },
    setDefault () {
      // 设置默认值
      let slots = this.getUseableSlots()
      if (this.dyOffset.length !== slots.length) {
        this.dyOffset = slots.map(s => {
          return 0
        })
      }
    },
    scrollBy (x = 0, y = 0) {
      // console.log('scrollBy', y)
      let scrollHeight = this.$refs.scrollBar ? this.$refs.scrollBar.offsetHeight : 300
      this.getUseableSlots().map((r, i) => {
        // console.log(r)
        let { offsetTop, clientHeight } = r.elm
        // console.log(offsetTop, scrollHeight)
        this.setDefault()
        let tY = this.dyOffset[i] + y
        if (y > 0) {
          // 向下滚动
          let top = offsetTop - tY + clientHeight
          if (top < 0) {
            tY = tY - scrollHeight // 放到最下面
          }
        } else {
          let top = offsetTop - tY + clientHeight
          if (top > scrollHeight) {
            // 放到最上面
            tY = tY + scrollHeight
          }
        }
        this.dyOffset[i] = tY
        r.elm.style.transform = `translateY(${-tY}px)`
      })
    },
    handleMouseWheel (e) {
      if (e.preventDefault) { 
        e.preventDefault()
      } else{
        e.returnValue = false
      }
      if (this.reqId) {
        cancelAnimationFrame(this.reqId) 
      }
      // 支持滚轮
      this.scrollBy(0, e.deltaY / 2) 
    },
    handleMouseEnter (e) {
      // 鼠标进入显示
      if (this.reqId) {
        cancelAnimationFrame(this.reqId) 
      }
      this.pause = true
    },
    handleMouseOut (e) {
      if (e.preventDefault) { 
        e.preventDefault()
      } else{
        e.returnValue = false
      }
      let src = e.srcElement || e.fromElement
      // 鼠标移出开始滚动
      if (src.className === 'scroll-list') {
        this.pause = false 
      }
    }
  }

}
</script>

<style scoped>
.scroll-list {
  height: 100%;
  overflow: hidden;
  position: relative;
}
</style>
